package com.wirelesspienetwork.overview.misc;

import ohos.agp.components.Component;
import ohos.agp.utils.Matrix;
import ohos.agp.utils.Rect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

public class Utilities {

    // Reflection methods for altering shadows
    private static Method sPropertyMethod;
    static {
        try {
            Class<?> c = Class.forName("android.view.GLES20Canvas");
            sPropertyMethod = c.getDeclaredMethod("setProperty", String.class, String.class);
            if (!sPropertyMethod.isAccessible()) sPropertyMethod.setAccessible(true);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    /** Scales a rect about its centroid
     * @param  r
     * @param scale*/
    public static void scaleRectAboutCenter(Rect r, float scale) {
        if (scale != 1.0f) {
            int cx = r.getCenterX();
            int cy = r.getCenterY();
            r.offset(-cx, -cy);
            r.left = (int) (r.left * scale + 0.5f);
            r.top = (int) (r.top * scale + 0.5f);
            r.right = (int) (r.right * scale + 0.5f);
            r.bottom = (int) (r.bottom * scale + 0.5f);
            r.offset(cx, cy);
        }
    }

    /** Maps a coorindate in a descendant view into the parent.
     * @param descendant
     * @param root
     * @param coord
     * @param includeRootScroll
     * @return float*/
    public static float mapCoordInDescendentToSelf(Component descendant, Component root,
                                                   float[] coord, boolean includeRootScroll) {
        ArrayList<Component> ancestorChain = new ArrayList<Component>();

        float[] pt = {coord[0], coord[1]};

        Component v = descendant;
        while(v != root && v != null) {
            ancestorChain.add(v);
            v = (Component) v.getComponentParent();
        }
        ancestorChain.add(root);

        float scale = 1.0f;
        int count = ancestorChain.size();
        for (int i = 0; i < count; i++) {
            Component v0 = ancestorChain.get(i);
            // For TextViews, scroll has a meaning which relates to the text position
            // which is very strange... ignore the scroll.
            if (v0 != descendant || includeRootScroll) {
                pt[0] -= v0.getScrollValue(Component.HORIZONTAL);
                pt[1] -= v0.getScrollValue(Component.VERTICAL);
            }

            pt[0] += v0.getLeft();
            pt[1] += v0.getTop();
            scale *= v0.getScaleX();
        }

        coord[0] = pt[0];
        coord[1] = pt[1];
        return scale;
    }

    /** Maps a coordinate in the root to a descendent.
     * @param descendant
     * @param root
     * @param coord
     * @param tmpInverseMatrix
     * @return float*/
    public static float mapCoordInSelfToDescendent(Component descendant, Component root,
                                                   float[] coord, Matrix tmpInverseMatrix) {
        ArrayList<Component> ancestorChain = new ArrayList<Component>();

        float[] pt = {coord[0], coord[1]};

        Component v = descendant;
        while(v != root) {
            ancestorChain.add(v);
            v = (Component) v.getComponentParent();
        }
        ancestorChain.add(root);

        float scale = 1.0f;
        int count = ancestorChain.size();
        tmpInverseMatrix.setMatrix(new Matrix());
        for (int i = count - 1; i >= 0; i--) {
            Component ancestor = ancestorChain.get(i);
            Component next = i > 0 ? ancestorChain.get(i-1) : null;

            pt[0] += ancestor.getScrollValue(Component.HORIZONTAL);
            pt[1] += ancestor.getScrollValue(Component.VERTICAL);

            if (next != null) {
                pt[0] -= next.getLeft();
                pt[1] -= next.getTop();
                tmpInverseMatrix.mapPoints(pt);
                scale *= next.getScaleX();
            }
        }

        coord[0] = pt[0];
        coord[1] = pt[1];
        return scale;
    }

    /** Sets some private shadow properties.
     * @param property
     * @param value
     * @throws IllegalAccessException
     * @throws InvocationTargetException */
    public static void setShadowProperty(String property, String value)
            throws IllegalAccessException, InvocationTargetException {
        if (sPropertyMethod != null) {
            sPropertyMethod.invoke(null, property, value);
        }
    }
}
